/* @vitest-environment node */ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; import fs from "node:fs/promises"; import os from "node:os"; import path from "node:path"; vi.mock("@/lib/auth/session", () => ({ getSession: vi.fn(), })); import { getSession } from "@/lib/auth/session"; import { GET, dynamic } from "./route.js"; describe("GET /api/branches/[branch]/years", () => { let tmpRoot; const originalNasRoot = process.env.NAS_ROOT_PATH; beforeEach(async () => { vi.clearAllMocks(); tmpRoot = await fs.mkdtemp(path.join(os.tmpdir(), "api-years-")); process.env.NAS_ROOT_PATH = tmpRoot; // Minimal structure for NL01 await fs.mkdir(path.join(tmpRoot, "NL01", "2024"), { recursive: true }); }); afterEach(async () => { process.env.NAS_ROOT_PATH = originalNasRoot; if (tmpRoot) await fs.rm(tmpRoot, { recursive: true, force: true }); }); it('exports dynamic="force-dynamic" (RHL-006)', () => { expect(dynamic).toBe("force-dynamic"); }); it("returns 401 when unauthenticated", async () => { getSession.mockResolvedValue(null); const res = await GET( new Request("http://localhost/api/branches/NL01/years"), { params: Promise.resolve({ branch: "NL01" }) } ); expect(res.status).toBe(401); expect(await res.json()).toEqual({ error: { message: "Unauthorized", code: "AUTH_UNAUTHENTICATED" }, }); }); it("returns 403 when branch user accesses a different branch", async () => { getSession.mockResolvedValue({ role: "branch", branchId: "NL01", userId: "u1", }); const res = await GET( new Request("http://localhost/api/branches/NL02/years"), { params: Promise.resolve({ branch: "NL02" }) } ); expect(res.status).toBe(403); expect(await res.json()).toEqual({ error: { message: "Forbidden", code: "AUTH_FORBIDDEN_BRANCH" }, }); }); it("returns years for a valid branch when allowed", async () => { getSession.mockResolvedValue({ role: "branch", branchId: "NL01", userId: "u1", }); const res = await GET( new Request("http://localhost/api/branches/NL01/years"), { params: Promise.resolve({ branch: "NL01" }) } ); expect(res.status).toBe(200); expect(await res.json()).toEqual({ branch: "NL01", years: ["2024"] }); }); it("returns 400 when branch param is missing (authenticated)", async () => { getSession.mockResolvedValue({ role: "admin", branchId: null, userId: "u2", }); const res = await GET(new Request("http://localhost/api/branches//years"), { params: Promise.resolve({ branch: undefined }), }); expect(res.status).toBe(400); expect(await res.json()).toEqual({ error: { message: "Missing required route parameter(s)", code: "VALIDATION_MISSING_PARAM", details: { params: ["branch"] }, }, }); }); it("returns 404 when the branch folder does not exist (authorized)", async () => { getSession.mockResolvedValue({ role: "admin", branchId: null, userId: "u2", }); const res = await GET( new Request("http://localhost/api/branches/NL99/years"), { params: Promise.resolve({ branch: "NL99" }) } ); expect(res.status).toBe(404); expect(await res.json()).toEqual({ error: { message: "Not found", code: "FS_NOT_FOUND", details: { branch: "NL99" }, }, }); }); it("returns 500 when NAS_ROOT_PATH is invalid (authenticated)", async () => { getSession.mockResolvedValue({ role: "admin", branchId: null, userId: "u2", }); process.env.NAS_ROOT_PATH = path.join(tmpRoot, "does-not-exist"); const res = await GET( new Request("http://localhost/api/branches/NL01/years"), { params: Promise.resolve({ branch: "NL01" }) } ); expect(res.status).toBe(500); expect(await res.json()).toEqual({ error: { message: "Internal server error", code: "FS_STORAGE_ERROR" }, }); }); });